package cc.android.testapp.xp.hooker;

import android.app.Application;

import org.json.JSONObject;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import cc.android.testapp.cfg.CFG;
import cc.android.testapp.cfg.ConfigHelper;
import cc.android.testapp.util.CLog;
import cc.android.testapp.util.CTool;
import cc.android.testapp.xp.HookBase;
import cc.android.testapp.xp.HookModule;
import cc.android.testapp.xp.hooker.adblock.util.XHook;
import cc.commons.util.reflect.FieldUtil;
import cc.commons.util.reflect.MethodUtil;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

@HookModule(packages = "tv.danmaku.bili", name = "哔哩哔哩")
public class HookBili extends HookBase implements ConfigHelper.IConfig {

    @CFG
    private boolean mEnableLog = true;
    @CFG
    private String mStartPageAdMethod = "tv.danmaku.bili.MainActivityV2.W7";
    @CFG
    private String mPlayPageAdMethod = "com.bilibili.ship.theseus.ugc.ad.DetailAdService$1.invokeSuspend";
    @CFG
    private String mHotPageAdMethod = "tv.danmaku.bili.ui.splash.service.a.c";

    @Override
    public void onConfigChange(JSONObject pNode) {
        this.mOldCfgStr = CTool.fieldVToStr(this);
        loadAnnoConfig(pNode);
    }

    @Override
    public String getCfgNode() {
        return "bili";
    }

    @Override
    protected void hookToApp(XC_LoadPackage.LoadPackageParam pParam, Application pApp) throws Throwable {
        ClassLoader tLoader = pApp.getClassLoader();
        Class<?> tClazz;
        try {
            tClazz = tLoader.loadClass("tv.danmaku.android.log.internal.Logger");
            XC_MethodHook tHook = new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    if (mEnableLog) CLog.log(Arrays.toString(param.args));
                }
            };
            for (String sStr : new String[]{"c", "e", "f", "g"}) {
                Method tM = MethodUtil.getMethodIgnoreParam(tClazz, sStr, true).oneGet();
                XposedBridge.hookMethod(tM, tHook);
            }
        } catch (Throwable exp) {
            CLog.log("Hook Bilibili Logger时发生错误", exp);
        }

        try {
            XHook.with(tLoader).match(new HBMethod(mStartPageAdMethod)).doNothing();
        } catch (Throwable exp) {
            CLog.log("Hook Bilibili启动页广告时发生错误", exp);
        }

        try {
            XHook.with(tLoader).match(new HBMethod(mHotPageAdMethod)).doNothing();
        } catch (Throwable exp) {
            CLog.log("Hook Bilibili恢复启动页广告时发生错误", exp);
        }

        try {
            tClazz = tLoader.loadClass("kotlin.Unit");
            Object _Unit_INSTANCE = FieldUtil.getStaticFieldValue(tClazz, "INSTANCE");

            XHook.with(tLoader).match(new HBMethod(mPlayPageAdMethod)).returnConstant(_Unit_INSTANCE);
        } catch (Throwable exp) {
            CLog.log("Hook播放页广告时发生错误", exp);
        }

        try {
            tClazz = tLoader.loadClass("com.bilibili.pegasus.promo.index.IndexFeedFragmentV2");
            Class<?> tClazz_Item = tLoader.loadClass("com.bilibili.pegasus.api.model.BasicIndexItem");
            Method method_BasicIndexItem_isAdCard = MethodUtil.getDeclaredMethod(tClazz_Item, "isAdCard");

            MethodUtil.getMethodWithParam(tClazz, true, List.class).forEach(method -> {
                XposedBridge.hookMethod(method, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        List<?> tList = (List<?>) param.args[0];
                        if (tList == null || tList.isEmpty()) return;
                        Iterator<?> tIt = tList.iterator();
                        while (tIt.hasNext()) {
                            Object tItem = tIt.next();
                            if (!tClazz_Item.isInstance(tItem)) break;
                            if ((boolean) MethodUtil.invokeMethod(method_BasicIndexItem_isAdCard, tItem)) {
                                tIt.remove();
                            }
                        }
                    }
                });
            });
        } catch (Throwable exp) {
            CLog.log("Hook卡片广告时发生错误", exp);
        }
    }

}
